Basic Plot - Drawto in Assembler

← Zurück zum Forum

Ich stelle das Thema mal online zur Diskussion:

Eine Assemblerroutine maximal schnell und effektiv um ein Plot/Drawto in Antic D nachzubilden...

Ideen??

... ich lege mal los ...

  • wir brauchen wohl den Bresenham-Algorithmus. Im Grunde ganz einfach: Beim Zeichnen einer Geraden von Punkt A zu Punkt B hat man ja letztlich eine Steigung der Geraden. Man plottet im Grunde immer in eine Richtung - nämlich in die lange Achse und entscheiden dann (anhand der Steigung) ab und zu mal einen Punkt in die kurze Achse zu plotten und geht dann von da weiter. Das lässt sich dann in eine Routine umsetzen.

... vielen Dank. Sehr interessanter Artikel (wie immer bei Peter Finzel). Leider in Action! geschrieben. Action! ist sicherlich eine höchst interessante Sprache, die ich leider nicht nutze. Vielleicht kann man das mal irgendwie in Eclipse implementieren - das wäre doch was für Peter (JAC)?!

Schau mal in den MADS examples Ordner. Dort findest Du fast draw.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

Leider habe ich in meinen Mads-Ordnern kein fast-draw gefunden ....

Das ist etwas versteckt. Habe mal kurz im github geschaut. Ich weiß, dass auch noch mehr Beispiele drin waren. Hier aber eines:

line.asm im examples Ordner Screenshot_20230522_104818.jpg

Anhänge:

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

gefunden, läuft aber nicht....

Das ist nicht eigenständig, sondern gehört zur graphics library.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

... nun habe ich einige Vorlagen selber gesammelt und dank eurer Links auch Vorlagen und Alternativen gefunden ... alles toll und zum Teil sehr "fertig" aber auch komplex. Ich möchte aber eine ganz eigene Routine hier mit euch entwickeln, die möglichst schnell ist - am Ende wird sich zeigen, ob sie schnell und effektiv ist.

Wir wollen ja eine Gerade zeichnen und brauchen eigentlich die Steigung dafür. Die Steigung lässt sich einfach mathematisch bestimmen aus dem Quotienten der Differenzen der y- und x-Werte: m = (y2-y1)/(x2-x1) = dy / dx Am Ende vermeidet der Bresenham-Algorithmus dieses Teilen, da er prinzipiell zeitintensiv und schwierig ist.... ist das denn wirklich auch so. Ich muss ja zum zeichnen der Gerade nur einmal teilen - am Anfang - und danach setze ich nur noch die Pixel in Abhängigkeit der Steigung m. Wenn die Steigung m beispielsweise 3 beträgt, dann muss ich nach jeden Schritt nach vorne 3 Schritte hoch gehen usw.

Also muss zunächst eine schnelle Routine her fürs relativ einfache teilen:

        SEC
        LDA dy
loop        SBC dx
        INX
        BCS loop

Danach steht im Register x die Steigung. Die Routine braucht 5 Zyklen plus x (Anzahl der Durchgänge) mal 8 Zyklen. 2 Sonderfälle sortieren wir gleich am Anfang aus: Die vertikale und die horizontale Linie. Die zeichnen wir direkt. Alles andere wird mittels der Steigung m gezeichnet.

Dr. Irata schrieb: Ich muss ja zum zeichnen der Gerade nur einmal teilen - am Anfang - und danach setze ich nur noch die Pixel in Abhängigkeit der Steigung m. Wenn die Steigung m beispielsweise 3 beträgt, dann muss ich nach jeden Schritt nach vorne 3 Schritte hoch gehen usw.

Wenn die Steigung z.B. 2.5 ist, bekommst Du für die "Unterschlagung" der Nachkommastellen mit Deiner Assemblerroutine "lustige" Ergebnisse...

Ich bin gespannt...

... das ist wahr... bin auch mal gespannt. Den Fehler muss man evt. ausbügeln. Das Verfahren ist ja auch nur eine Art Näherung.

Dr. Irata schrieb: Den Fehler muss man evt. ausbügeln. Das Verfahren ist ja auch nur eine Art Näherung.

Der Fehler muss in den Algorithmus einfließen. Mit einem Algorithmus à la "nach zwei Pixel hoch, einen nach rechts" bekommst Du nicht immer eine Verbindung zwischen zwei Punkten: Unbenannt.png

Du kannst Dir eine Menge Zeit und Aufwand sparen (und hast dabei noch den schnellsten Algorithmus), wenn Du Bresenham anwendest...

Anhänge:

hmmmm.... warum das Rad neu erfinden, wenn es nicht sicher ist, ob es runder und besser ist, als das bereits bestehende... Der Bresenham-Algorithmus ist ja speziell damals für die Linienzeichnung entwickelt worden. Die Theorie ist dabei mathematisch relativ logisch und die Umsetzung einfach. Als Beispiel hier die Umsetzung in Basic:

REM Bresenham-Algorithmus für eine Linie im ersten Oktanten in Pseudo-Basic
dx = xend-xstart
dy = yend-ystart
REM im ersten Oktanten muss 0 < dy <= dx sein

REM Initialisierungen
x = xstart
y = ystart
SETPIXEL x,y
fehler = dx/2

REM Pixelschleife: immer ein Schritt in schnelle Richtung, hin und wieder auch einer in langsame
WHILE x < xend
   REM Schritt in schnelle Richtung
   x = x + 1
   fehler = fehler - dy
   IF fehler < 0 THEN
      REM Schritt in langsame Richtung
      y = y + 1
      fehler = fehler + dx
   END IF
   SETPIXEL x,y
WEND

... das kann man gut in Assembler konvertieren!

... nun habe ich es doch mal mit meiner Methode probiert - zunächst - und es klappt damit auch ganz gut. Die größte Schwierigkeit dabei war es eigentlich die Dinge mit einer vernünftigen Geschwindigkeit auch für später auf den Bildschirm zu bringen. Ich habe ja eine Auflösung von (40*4) * 96 und muss in horizontaler Richtung mit 4 Phasen incl. EOR Befehlen arbeiten, in vertikaler Richtung habe ich eine sehr lange Tabelle, damit ich nicht ständig den y-Displaywert berechnen muss. Und dann muss man ja auch noch 4 Fälle unterscheiden (dieser Ansatz macht nur eine Fall) - nämlich wenn die Steigung Minus und kleiner Eins ist. Eine kleine Gerade zeichnen auf Assembler... klingt sooo einfach und ist so schwierig!!!

jetzt habe ich mal für verschiedene Steigungen die Gerade mit Start- und Zielpunkt verglichen ... und oh Wunder, wie schon vermutet runde ich ja den "Fehler" einfach weg und das macht sich natürlich bemerkbar... die Gerade erreicht den Endpunkt meistens nicht ... Also wird nun der Algorithmus eingepflegt 😉

Nun habe ich den Algorithmus endlich korrekt umsetzen können. Ich habe also den einfachen Bresenham-Algorithmus genommen - dabei muss man beachten, daß er so nur für einen Quadranten gilt mit positiver Steigung... alle anderen Fälle lassen sich dann aber entsprechend ableiten. Ich habe das ganze für Antic D konzipiert, also wie oben beschrieben mit entsprechender Displaylist. Die Bewegung in y-Achse läuft über 2 lange Tabellen und in x-Achse mit Berücksichtigung der 4-Bit-Phasenverschiebung. Alles deutlich komplizierter als gedacht.... Meinen ersten Ansatz musste ich verwerfen, da zu ungenau. Der Bresenham-Algorithmus funktionierte bei mir nicht so wie gedacht, da fehlte noch ein x 4 bei dx ... keine Ahnung warum. Habe ich da irgendwo unbewusst ein /4 eingebaut?? 4x dx muss man vermeiden, da man bei hohen dx über die 255 Grenze kommt, also addiert man zum Fehler einfach 4x dx !! Jedenfalls so geht es jetzt ganz wunderbar!! Hier der Code vom Algorithmus, wer Interesse am Gesamtcode hat einfach melden... wäre das ein Extrabeitrag fürs Magazin?? 😀


            ;------ Bresenham-Algorithmus ----

            mva dx fehler
            lsr fehler      ; laut Bresenham wird der Fehler halbiert
@           
            #if .byte y1<y2   ; y1 = x und y2 = xend 
            ;-------- x=x+1-----
            ldy y1              ; mein x
            jsr xrichtung       ; Phasenverschiebung increment horizontal x+1
            ;-------------------
            sec
            lda fehler
            sbc dy
            sta fehler
            #if .byte fehler>#128  ; =<0
            ;--------- y=y+1-----
            inx                 ; mit x lade ich hier die Displaywerte aus einer Tabelle
            inx                 ; für die Bewegung in vertikaler Richtung, 2x inx wegen
            mwa convx,x jump            ; jeweils 2 Bytes auslesen - das geht dann als selbstmod.
                                ; Code bei jump1 rein --> jsr 0 springt dann jeweils an:
                                ; xx0       lda 256*156,y
                                ;           eor phase
                                ;           sta 256*156,y
                                ;           rts
            ;--------------------
            clc
            lda fehler
            adc dx              ; hier muss man 4x dx zum Fehler wieder addieren
            adc dx              ; also quasi fehler + 4 x dx (geht aber nicht für hohe dx - also 4 x addieren)
            adc dx
            adc dx
            sta fehler
            #end
            ;---------- Print Punkt ------
            jsr jump1
            ;-----------------------------

            jmp @-
            #end

            jmp *  ; Programm stoppt hier

jump1           jump = *+1          
            jsr 0
            rts


            ;-------------- Ende -----------------------------

            .proc xrichtung
            #if .byte horiz=#3
            mva #2 phase
            mva #0 horiz
            inc y1
            rts
            #end
            #if .byte horiz=#2
            mva #8 phase
            inc horiz
            rts
            #end
            #if .byte horiz=#1
            mva #32 phase
            inc horiz
            rts
            #end
            #if .byte horiz=#0
            mva #128 phase
            inc horiz
            rts
            #end
            rts
            .endp

Dr. Irata schrieb: wäre das ein Extrabeitrag fürs Magazin?? :D

Ja !!

https://mastodon.social/@cstrotm https://abbuc.social

... jetzt plötzlich - wie logisch - ist mir gerade klar geworden, warum ich den Faktor 4 für dx brauche, damit es stimmt.... meine Auflösung in x-Richtung ist ja theoretisch 160, aber da ich 4bit * 40 = 160 habe, rechne ich ja die ganze Zeit in x-Richtung mit 1/4... das macht natürlich den Algorithmus falsch - bzw. man muss das mit Faktor 4 korrigieren !!

Nun kann ich die anderen Fälle programmieren, damit kann man die Gerade in alle Richtungen zeichnen. Im Anschluss mache ich eine kleine animierte Demo...

Dr. Irata schrieb: Nun kann ich die anderen Fälle programmieren, damit kann man die Gerade in alle Richtungen zeichnen. Im Anschluss mache ich eine kleine animierte Demo...

Es werden weniger Fälle, wenn Start- und Endpunkt vorher getauscht werden, falls sie "ungünstig" liegen....

Noch ein Tipp: Beim 6502 ist es schneller man adressiert 16bit über 2 Tabellen (Hi- und Low-Byte getrennt).

Mal ein Auszug aus meiner Grafik-Lib:

; Calculates and returns actual adress of line respective to screen base address,
; row offset value and given y/line number
; BYTE* __fastcall__
; Screen_GetRowAddress(BYTE nRow_);

.export _Screen_GetRowAddress
.proc   _Screen_GetRowAddress
        tay                         ; line to table index
        lda _ScreenRowAdrTableL, Y  ; access table (low)
        ldx _ScreenRowAdrTableH, Y  ; access table (high)
        rts
.endproc

vielen vielen Dank für die inspirierende Ideen... schon cool, was alles möglich ist mit dem kleinen A8...

... also ich habe meine Tabelle / Tabellen folgendermaßen angelegt:

Wenn eine Bewegung vertikal erfolgt, lade ich per selbstmodifizierenden Code eine entsprechende 16 Bit Adresse (die ist und bleibt fix und steht daher am Beginn des Programmes) in den JSR-Befehl, per JSR springe ich dann jeweils zu der kleinen und kurzen Routine, die den Plot in der jeweiligen Zeile macht. Jegliche Rechnerei wird dadurch vermieden... ob das jetzt besonders schnell und gut ist, weiß ich nicht - besser als dauernd berechnen sicherlich.

...
        mwa convx,x  jump       ; dies ist der selbstmodifizierende Part
...


...
jump1           jump = *+1      ; aus der Tabelle conv erhält jump die Sprungadresse, durch *+1 wird die adresse hinter jsr gelegt  
            jsr 0
            rts
....

;Tabelle der einzelnen Adressen - für jede Zeile eine:

convx   .word $2200,$220a,$2214,$221e,$2228,$2232,$223c,$2246
        .word $2250,$225a,$2264,$226e,$2278,$2282,$228c,$2296
        .word $22a0,$22aa,$22b4,$22be,$22c8,$22d2,$22dc,$22e6
        .word $22f0,$22fa,$2304,$230e,$2318,$2322,$232c,$2336

        .word $2340,$234a,$2354,$235e,$2368,$2372,$237c,$2386
        .word $2390,$239a,$23a4,$23ae,$23b8,$23c2,$23cc,$23d6
        .word $23e0,$23ea,$23f4,$23fe,$2408,$2412,$241c,$2426
        .word $2430,$243a,$2444,$244e,$2458,$2462,$246c,$2476

        .word $2480,$248a,$2494,$249e,$24a8,$24b2,$24bc,$24c6
        .word $24d0,$24da,$24e4,$24ee,$24f8,$2502,$250c,$2516
        .word $2520,$252a,$2534,$253e,$2548,$2552,$255c,$2566
        .word $2570,$257a,$2584,$258e,$2598,$25a2,$25ac,$25b6

; ein Ausschnitt der Plotroutinen. Diese beginnt zwingend bei $2200

xx0     lda 256*156,y
        eor phase
        sta 256*156,y
        rts

xx1     lda 256*156+50,y
        eor phase
        sta 256*156+50,y
        rts

xx2     lda 256*156+100,y
        eor phase
        sta 256*156+100,y
        rts

xx3     lda 256*156+150,y
        eor phase
        sta 256*156+150,y
        rts

xx4     lda 256*156+200,y
        eor phase
        sta 256*156+200,y
        rts
        .......
xx95        lda 256*175,y
        eor phase
        sta 256*175,y
        rts

Irgendwer schrieb: Noch ein Tipp: Beim 6502 ist es schneller man adressiert 16bit über 2 Tabellen (Hi- und Low-Byte getrennt).

Mal ein Auszug aus meiner Grafik-Lib:

``` ; Calculates and returns actual adress of line respective to screen base address, ; row offset value and given y/line number ; BYTE* fastcall ; Screen_GetRowAddress(BYTE nRow_);

.export _Screen_GetRowAddress .proc _Screen_GetRowAddress tay ; line to table index lda _ScreenRowAdrTableL, Y ; access table (low) ldx _ScreenRowAdrTableH, Y ; access table (high) rts .endproc ```

bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???

Dr. Irata schrieb: bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???

Halleluja, so wie Du das gemacht hast, wäre mir gar nicht eingefallen. Mit haben schon die z.B. 192*2 Bytes (Antic F) für die Zeilenadresstabelle weh getan, aber für jede Zeile noch mal 9 Bytes für die Plot-Routine ist schon beachtlich - auch deswegen, weil Du für typische Anwendungsfälle nicht mit EOR auskommst, sondern AND zum Löschen und OR zum "Zeichnen" brauchst (was den Code nochmal aufbläht).

Ich benutze nicht MADS und tue mich mit den "mwa/mva"-Macros immer schwer. Aber optimal scheint mir das Vorgehen nicht zu sein. (Ich verstehe auch nicht ganz Deinen +50, +100, +150 Offset (falls Du nicht eine spezielle Display-List hast, sollten Deine Zeilen 40 Bytes breit sein...?))

Ganz klassisch würde das EOR-Plotten ungefähr so aussehen:

; Routine zum Plotten, X = x-Koordinate; Y = Y-Koordinate, zpPtr = 16-Bit Wort in der Zero-Page
Plot:
        lda _ScreenRowAdrTableL, Y  ; access table (low)
        sta zpPtr
        lda _ScreenRowAdrTableH, Y  ; access table (high)
        sta zpPtr+1
        txa                             ; 
        lsr a                           ; / 2
        lsr a                           ; / 4 ( 4 Pixel / Byte )
        tay                             ; = zeilen offset

        ; hier könnte code stehen der 'phase' (aus Deinem Code) errechnet
        ; aus der X-coordinate 2 bits nimmt für eine Maske aus einer Tabelle
        ; txa
        ; and #3
        ; tax
        ; lda PixelMask, x      ; farbabhängig 
        ; sta phase

        lda (zpPtr), Y
        eor phase
        sta (zpPtr), Y

        rts

PixelMask:
.byte   %00000011
.byte   %00001100
.byte   %00110000
.byte   %11000000

Es gibt noch genug zum Austoben: Der Trick bei einer Linienroutine ist nicht einzelne Pixel zu plotten, sondern das Wissen, dass sie benachbart sind code-technisch elegant auszunutzen... (z.B. selbe Zeile, selbes Byte etc.)

Noch ein Tipp: Statt

            jsr irgendwohin
            rts

kann man auch

            jmp irgendwohin

schreiben und spart Zeit und ein Byte...

Und noch ein Hinweis: Die Literatur, die 'cas' hier verlinkt hat ist sicherlich interessant, aber wenn sie für den C64 ist sehr mit Vorsicht zu genießen. Der C64 hat ein ganz anderen Bildschirmspeicheraufbau, was die Sache noch komplizierter macht...

Weiterhin viel Spaß beim Entdecken!

... tatsächlich hatte ich aus älteren Überlegungen (Feinscrol/Grobscrol) die Displaylist ganz anders aufgebaut. Für horizontales Feinscrolling braucht man ja eine Breite von 48 statt 40 (ich habe gleich 50 genommen, weil es mir übersichtlicher erschien) - jede Zeil der Displaylist hat entsprechend einen eigenen Sprungbefehl mit entsprechender Adresse wegen des dann auch zu erwartenden Grobscroll mit Displaylistmanipulation. Da ich aber keinen Feinscroll brauche bei dem Programm, macht es Sinn, die Displaylist wieder ganz normal zu strukturieren. Die Plotroutine sieht gut aus - ich werde das umbauen. Danke für alle Hinweise...

Irgendwer schrieb:

Dr. Irata schrieb: bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???

Halleluja, so wie Du das gemacht hast, wäre mir gar nicht eingefallen. Mit haben schon die z.B. 192*2 Bytes (Antic F) für die Zeilenadresstabelle weh getan, aber für jede Zeile noch mal 9 Bytes für die Plot-Routine ist schon beachtlich - auch deswegen, weil Du für typische Anwendungsfälle nicht mit EOR auskommst, sondern AND zum Löschen und OR zum "Zeichnen" brauchst (was den Code nochmal aufbläht).

Ich benutze nicht MADS und tue mich mit den "mwa/mva"-Macros immer schwer. Aber optimal scheint mir das Vorgehen nicht zu sein. (Ich verstehe auch nicht ganz Deinen +50, +100, +150 Offset (falls Du nicht eine spezielle Display-List hast, sollten Deine Zeilen 40 Bytes breit sein...?))

Ganz klassisch würde das EOR-Plotten ungefähr so aussehen:

``` ; Routine zum Plotten, X = x-Koordinate; Y = Y-Koordinate, zpPtr = 16-Bit Wort in der Zero-Page Plot: lda _ScreenRowAdrTableL, Y ; access table (low) sta zpPtr lda _ScreenRowAdrTableH, Y ; access table (high) sta zpPtr+1 txa ; lsr a ; / 2 lsr a ; / 4 ( 4 Pixel / Byte ) tay ; = zeilen offset

  ; hier könnte code stehen der 'phase' (aus Deinem Code) errechnet
  ; aus der X-coordinate 2 bits nimmt für eine Maske aus einer Tabelle
  ; txa
  ; and #3
  ; tax
  ; lda PixelMask, x      ; farbabhängig 
  ; sta phase

  lda (zpPtr), Y
  eor phase
  sta (zpPtr), Y

  rts

PixelMask: .byte %00000011 .byte %00001100 .byte %00110000 .byte %11000000 ```

Es gibt noch genug zum Austoben: Der Trick bei einer Linienroutine ist nicht einzelne Pixel zu plotten, sondern das Wissen, dass sie benachbart sind code-technisch elegant auszunutzen... (z.B. selbe Zeile, selbes Byte etc.)

Noch ein Tipp: Statt

jsr irgendwohin rts

kann man auch

jmp irgendwohin

schreiben und spart Zeit und ein Byte...

Und noch ein Hinweis: Die Literatur, die 'cas' hier verlinkt hat ist sicherlich interessant, aber wenn sie für den C64 ist sehr mit Vorsicht zu genießen. Der C64 hat ein ganz anderen Bildschirmspeicheraufbau, was die Sache noch komplizierter macht...

Weiterhin viel Spaß beim Entdecken!

... mit welcher Umgebung programmierst du denn??

cas schrieb: Und noch zwei Artikel gefunden:

Eine Info zum C64 und dessen HiRes Grafik.

  • Beim AtariXL ist die Grafik wirklich Zeilenweise angeordnet. Also das das nächste Byte (+1) liegt in der selben Zeile nur halt ein paar Pixel weiter rechts.

Ein Index sieht so aus... 0, 1, 2, 3, ... 39, 40,41,42... ...

  • Beim C64 ist die Anordnung eher wie beim Zeichensatz. 8 Bytes untereinander, dann kommen die nächsten 8 Bytes untereinander...

Ein Index beim C64 sieht so aus... 0,8,16,24, ... 312, 1,9,17, 2,10,18, 3,11,19, ... 7,15,23,...

320,328,... 321,... ...

Das sollte man berücksichtigen, wenn man sich C64-Linienalgorithmen ansieht und versucht diese zu verstehen.

LG Lars

Ich bin auch kein Fan von MADS und mva/mwa. Das wird sich erst ändern, wenn es den Assembler native auf Linux gibt. BTW: Wine ist nicht Linux.

LarsImNetz schrieb: Ich bin auch kein Fan von MADS und mva/mwa. Das wird sich erst ändern, wenn es den Assembler native auf Linux gibt. BTW: Wine ist nicht Linux.

Hallo Lars,

warum "wenn", den gibt es doch schon lange (eigendlich seit immer) "nativ" unter Linux:

apt install fpc
git clone https://github.com/tebe6502/Mad-Assembler
cd Mad-Assembler
fpc -Mdelphi -vh -O3 mads.pas
sudo cp mads /usr/local/bin

Ich kann Dir gerne auch ein "mads" binary für i686/amd64/arm/aarch64/m68k kompilieren.

https://mastodon.social/@cstrotm https://abbuc.social

passt schon, hab ihn gerade selbst gebaut.

So, hier mal eine etwas schnellere Line-Zeichen-Routine. Es gab mal irgendwo einen Source mit 8 Versionen, das hier ist die letzte davon.

Die Routine schafft locker 300 Linien pro Sekunde. (rand(160), rand(192),rand(160), rand(192)) ist leider etwas ungenau, dafür verdammt flott.

Die Parameterübergabe ist für meinen Compiler, ähnlich wie beim cc65. Per (heap_ptr),y realisiert. Wenn man sich die komplizierte, teure Parameterübergabe spart, ist diese Routine noch schneller. Der Code ist kompatibel zum Atasm Assembler. Der Code zeichnet 4 Pixel gleichzeitig, mehr hab ich bisher auch nicht verstanden.

Wirklich das schnellste, was ich bisher gesehen habe. Ich habe auch den Code von ERU, zum Vergleich, die schafft ca. 216 Linien pro Sekunde, nur um mal ein paar Zahlen zu nennen. Mit einfachem Bresenham komme ich in meinem Compiler nicht über 80 Linien pro Sekunde, was aber am expliziten PLOT(x,y) liegt.

Wer die Routine nutzen möchte, sollte die @MULT40_low und _high Tabelle noch setzen, hab ich hier nicht mit angegeben.

LG Lars

  .LOCAL

; TODO
; Dieser LINE Algorithmus funktioniert nur
; in graphics 7 und 15 (40 Bytes breit)
; bis 160 x 192!!! Weil nur 8 Bit breit
; ist dafuer sehr schnell, leider ungenau => eher unbrauchbar

; BITMSK    = $6E
; SHFAMT    = $6F
;ROWCRS = $54
;COLCRS = $55
;OLDROW = $5A
;OLDCOL = $5B
;ROWAC  = $70
;ROWADC     = $72
;CFLAG  = $74
;RFLAG  = $75
;DELTAROW= $76
;DELTACOL= $77
;ATACHR = $02FB

;opcodes for self-modifying code
?_OC_BIT_0P_ = $24
?_OC_DEC_0P_ = $C6 ;11000110
?_OC_INC_0P_ = $E6 ;11100110 ;XOR 32 ;$20
?_OC_DEX_   = $CA  ;11001010
?_OC_INX_   = $E8  ;11101000 ;XOR 34 ;$22
?_OC_AND_AX_ = $3D
?_OC_EOR_AX_ = $5D
?_OC_ORA_AX_ = $1D

; @REG ist bei mir ab Adresse 220 (Floating-Point-Register) 
?L0  = @REG+0 ; $B0
?L1  = @REG+1 ; $B1

?L2  = @REG+2 ; $B2
?L3  = @REG+3 ; $B3

?L4  = @REG+4 ; $B4
?L5  = @REG+5 ; $B5

?L6  = @REG+6 ; $B6
?L7  = @REG+7 ; $B7

?m0 = @REG+8
?m1 = @REG+9
?m2 = @REG+10

?x0 = @REG+11
?x1 = @REG+12
?x2 = @REG+13


@SETLINECOLOR
@SETLINECOLOR_i
        LDY #1            ; color 0 - 3
        LDA (@HEAP_PTR),Y ; wert holen
        and #3
        TAX

    LDY ?MASTSET,X
    STY ?SET1IMASKT
    STY ?SET1IMASKW
    STY ?SET2IMASKT
    STY ?SET2IMASKW
    STY ?SET3IMASKT
    STY ?SET3IMASKW
    STY ?SET4IMASKT
    STY ?SET4IMASKW
    LDA ADRCOLMHI,X
    STA ?GET1CMASKHT
    STA ?GET1CMASKHW
    STA ?GET2CMASKHT
    STA ?GET2CMASKHW
    STA ?GET3CMASKHT
    STA ?GET3CMASKHW
    STA ?GET4CMASKHT
    STA ?GET4CMASKHW
    RTS


; DRAWLINE ;v6
;   LDA #1
;   STA OLDROW
;   LDA #153
;   STA OLDCOL
;   LDA #072
;   STA ROWCRS
;   LDA #1
;   STA COLCRS
@LINE
@LINE_IIII
@FASTLINE2BIT
@FASTLINE2BIT_IIII
  LDY #1            ; XSTART
  LDA (@HEAP_PTR),Y ; wert holen
  STA OLDCOL ; ?XSTART

  LDY #3            ; YSTART
  LDA (@HEAP_PTR),Y ; wert holen
  STA OLDROW ; ?YSTART

  LDY #5            ; XEND
  LDA (@HEAP_PTR),Y ; wert holen
  STA COLCRS ; ?XEND

  LDY #7            ; YEND
  LDA (@HEAP_PTR),Y ; wert holen
  STA ROWCRS ; ?YEND

  LDA OLDROW
    SEC
    SBC ROWCRS
    BCS ?OLDROWFIRST

    LDX OLDCOL ;3
    LDY COLCRS ;3
    STY OLDCOL ;3
    STX COLCRS ;3
    LDY OLDROW
    SBC #0
    EOR #255
    JMP ?STOREROWDELTA

?OLDROWFIRST
    LDY ROWCRS

?STOREROWDELTA
    STA ?aw_WIDE_DELTA_RI
    STA ?aw_TALL_DELTA_RI
    LSR A
    LSR A
    STA ?X1
    BNE ?NOVS2
    BCC ?NOVS2
    LDA #01
?NOVS2
    STA ?m2
    LDA @MULT40_LOW,Y
    STA ?L0
    LDA @MULT40_HIGH,Y
    STA ?L1

    TYA
    CLC
    ADC ?X1
    TAY
    LDA @MULT40_LOW,Y
    STA ?L2
    LDA @MULT40_HIGH,Y
    STA ?L3

    TYA
    CLC
    ADC ?m2
    TAY
    LDA @MULT40_LOW,Y
    STA ?L4
    LDA @MULT40_HIGH,Y
    STA ?L5

    TYA
    CLC
    ADC ?X1
    TAY
    LDA @MULT40_LOW,Y
    STA ?L6
    LDA @MULT40_HIGH,Y
    STA ?L7

    LDA OLDCOL
    SEC
    SBC COLCRS
    BCS ?aw_HOZ_POS

?aw_HOZ_NEG
    SBC #0
    EOR #255
    TAY
    LSR A
    LSR A
    STA ?m1
    STA ?x0
    STA ?X2
    BNE ?noHS1
    BCC ?noHS1

    LDA #1
?noHS1
    STA ?m2

    LDA COLCRS
    SEC
    SBC ?X2
    STA ?GET1CMASKLW
    STA ?GET1TABLW
    STA ?GET1CMASKLT
    STA ?GET1TABLT

    SBC ?m2
    STA ?GET2CMASKLW
    STA ?GET2TABLW
    STA ?GET2CMASKLT
    STA ?GET2TABLT

    SBC ?X2
    STA ?GET3CMASKLW
    STA ?GET3TABLW
    STA ?GET3CMASKLT
    STA ?GET3TABLT

    SBC ?X2
    STA ?GET4CMASKLW
    STA ?GET4TABLW
    STA ?GET4CMASKLT
    STA ?GET4TABLT
    LDX #?_OC_DEX_
    JMP ?compARE_SLOPE

?aw_HOZ_POS
    TAY
    LSR A
    LSR A
    STA ?X2
    BNE ?noHS2
    BCC ?noHS2

    LDA #01
?noHS2
    STA ?m2
    LDA COLCRS
    STA ?GET1CMASKLW
    STA ?GET1TABLW
    STA ?GET1CMASKLT
    STA ?GET1TABLT

    CLC
    ADC ?X2
    STA ?GET2CMASKLW
    STA ?GET2TABLW
    STA ?GET2CMASKLT
    STA ?GET2TABLT

    ADC ?m2
    STA ?GET3CMASKLW
    STA ?GET3TABLW
    STA ?GET3CMASKLT
    STA ?GET3TABLT

    ADC ?X2
    STA ?GET4CMASKLW
    STA ?GET4TABLW
    STA ?GET4CMASKLT
    STA ?GET4TABLT
    STA ?m0

    LDX #0
    STX ?x0
    LDX #?_OC_INX_
?compARE_SLOPE
    CPY ?aw_WIDE_DELTA_RI
    BCC ?aw_TALLSLOPE
    BEQ ?aw_TALLSLOPE

?aw_WIDESLOPE
    STY ?aw_WIDE_DELTA_CI
    TYA
    SEC
    SBC ?m2
    STA ?m1
  STX ?COLADC1
    LDA ?X2
    BEQ ?aw_WIDESLOPE0

    SEC
    LDX ?x0
?aw_WIDE_LOOP

?COLADC1
    INX         ;2
?GET1TABLW = *+1
    LDY ?TAB4DIV,X      ;6
    LDA (?L0),Y     ;11
?SET1IMASKW = *
?GET1CMASKLW = *+1
?GET1CMASKHW = *+2
    ORA $FF00,X     ;15
    STA (?L0),Y     ;20

?GET2TABLW = *+1
    LDY ?TAB4DIV,X      ;24
    LDA (?L2),Y     ;29
?SET2IMASKW = *
?GET2CMASKLW = *+1
?GET2CMASKHW = *+2
    ORA $FF00,X     ;33
    STA (?L2),Y     ;38

?GET3TABLW = *+1
    LDY ?TAB4DIV,X      ;42
    LDA (?L4),Y     ;47
?SET3IMASKW = *
?GET3CMASKLW = *+1
?GET3CMASKHW = *+2
    ORA $FF00,X     ;51
    STA (?L4),Y     ;56

?GET4TABLW = *+1
    LDY ?TAB4DIV,X      ;60
    LDA (?L6),Y     ;65
?SET4IMASKW = *
?GET4CMASKLW = *+1
?GET4CMASKHW = *+2
    ORA $FF00,X     ;69
    STA (?L6),Y     ;74

    LDA ?m1         ;77 -3
?aw_WIDE_DELTA_RI=*+1
    SBC #$FF        ;79 -5
    STA ?m1         ;82 -8
    BCS ?aw_WIDE_SKIP   ;85
?aw_WIDE_DELTA_CI=*+1
    ADC #$FF
    STA ?m1

    LDA ?L0
    CLC
    ADC #40
    STA ?L0
    BCC ?no_WIDE_H1INC
    INC ?L1

    CLC
?no_WIDE_H1INC
    LDA ?L2
    ADC #40
    STA ?L2
    BCC ?no_WIDE_H2INC
    INC ?L3

    CLC
?no_WIDE_H2INC
    LDA ?L4
    ADC #40
    STA ?L4
    BCC ?no_WIDE_H3INC
    INC ?L5

    CLC
?no_WIDE_H3INC
    LDA ?L6
    ADC #40
    STA ?L6
    BCC ?no_WIDE_H4INC
    INC ?L7
?no_WIDE_H4INC

    SEC
?aw_WIDE_SKIP

?LAST_WIDE_X = *+1
    DEC ?X2         ;88
    BNE ?aw_WIDE_LOOP   ;91

?aw_WIDESLOPE0
    RTS

;
?aw_TALLSLOPE
    STY ?aw_TALL_DELTA_CI
    LDA ?aw_TALL_DELTA_RI
    SEC
    SBC ?m2
    STA ?m1
    DEC ?X1
    BEQ ?aw_WIDESLOPE0
    BMI ?aw_WIDESLOPE0
  STX ?COLADC2
    LDX ?x0
?aw_TALL_LOOP

?GET1TABLT = *+1
    LDY ?TAB4DIV,X   ;4
    LDA (?L0),Y      ;9
?SET1IMASKT = *
?GET1CMASKLT = *+1
?GET1CMASKHT = *+2
    ORA $FF00,X        ;14
    STA (?L0),Y      ;19

?GET2TABLT = *+1
    LDY ?TAB4DIV,X   ;23
    LDA (?L2),Y      ;28
?SET2IMASKT = *
?GET2CMASKLT = *+1
?GET2CMASKHT = *+2
    ORA $FF00,X        ;32
    STA (?L2),Y      ;37

?GET3TABLT = *+1
    LDY ?TAB4DIV,X   ;4
    LDA (?L4),Y      ;9
?SET3IMASKT = *
?GET3CMASKLT = *+1
?GET3CMASKHT = *+2
    ORA $FF00,X        ;14
    STA (?L4),Y      ;19

?GET4TABLT = *+1
    LDY ?TAB4DIV,X   ;23
    LDA (?L6),Y      ;28
?SET4IMASKT = *
?GET4CMASKLT = *+1
?GET4CMASKHT = *+2
    ORA $FF00,X        ;32
    STA (?L6),Y      ;37

    LDA ?m1            ;40
    SEC                ;42
?aw_TALL_DELTA_CI=*+1
    SBC #$FF    ;44
    BCS ?aw_TALL_SKIP ;47
?aw_TALL_DELTA_RI=*+1
    ADC #$FF    ;

?COLADC2
    INX
?aw_TALL_SKIP
    STA ?m1     ;50

    LDA ?L0     ;53
    CLC     ;55
    ADC #40     ;57
    STA ?L0     ;60
    BCC ?no_TALL_H1INC ;63
    INC ?L1

    CLC
?NO_TALL_H1INC
    LDA ?L2     ;66
    ADC #40     ;68
    STA ?L2     ;71
    BCC ?no_TALLH2DEC ;74
    INC ?L3

?NO_TALLH2DEC
    LDA ?L4     ;53
    CLC     ;55
    ADC #40     ;57
    STA ?L4     ;60
    BCC ?no_TALL_H3INC ;63
    INC ?L5

    CLC
?NO_TALL_H3INC
    LDA ?L6     ;66
    ADC #40     ;68
    STA ?L6     ;71
    BCC ?NO_TALLH4DEC ;74
    INC ?L7

?NO_TALLH4DEC

    DEC ?X1     ;77
    BPL ?AW_TALL_LOOP ;80
?DREND
    RTS

  * = (* +$FF) & $FF00

ANDMASK
    .byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
    .byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
    .byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
    .byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
    .byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252

ADRCOLMLO
    .byte <ANDMASK, <COLORMASK1, <COLORMASK2, <COLORMASK3
ADRCOLMHI
    .byte >ANDMASK, >COLORMASK1, >COLORMASK2, >COLORMASK3

?MASTSET
        .byte ?_OC_AND_AX_, ?_OC_ORA_AX_, ?_OC_ORA_AX_, ?_OC_ORA_AX_
        .byte ?_OC_AND_AX_, ?_OC_EOR_AX_, ?_OC_EOR_AX_, ?_OC_EOR_AX_

;M1DIMG
;   .byte 3,12,48,192
;M2DIMG
;   .byte 1,4,16,64

;EMPTYDATA
;   .byte 0,0,0,0

;   ORG LINEDATAPAGE + 256
  * = (* +$FF) & $FF00
COLORMASK1
    .byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
    .byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
    .byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
    .byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
    .byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1

;   ORG LINEDATAPAGE + 512
  * = (* +$FF) & $FF00
COLORMASK2
    .byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
    .byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
    .byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
    .byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
    .byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2

;   ORG LINEDATAPAGE + 768
  * = (* +$FF) & $FF00
COLORMASK3
    .byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
    .byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
    .byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
    .byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
    .byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3

;   ORG LINEDATAPAGE + 1024
  * = (* +$FF) & $FF00

?TAB4DIV
    .byte 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9
    .byte 10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19
    .byte 20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29
    .byte 30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,37,37,37,37,38,38,38,38,39,39,39,39


    .align 256

; muessen initialisiert werden! Die zeigen auf den Graphics-Speicher, jeder Wert ist um 40 Bytes groesser

@MULT40_low
 .dc 256 0

@MULT40_high
 .dc 256 0

... ich sehe schon, das Thema gibt eine Menge her. Nach welchem mathematischen Prinzip arbeiten denn diese schnellen Lösungen?

Dr. Irata schrieb: ... mit welcher Umgebung programmierst du denn??

cc65/ca65

eigentlich versuche ich inzwischen soviel wie geht in cc65 zu schreiben und erst wenn es zeitkritisch wird, entweder cc65 zu verbessern 😀 oder auf Assembler zu wechseln. Klappt bisher ganz gut.

Größte Hürde bei cc65 ist, wenn man es denn irgendwann kann, gleichzeitig die größte Hilfe: Die Linker-Configuration. Gerade beim Atari mit seinen vielen Speicherausrichtungsanforderungen (Zeichensätze, PMG, DL, Bildschirmspeicher) ist das am Anfang kompliziert - inzwischen aber für die Atari-Compound-Dateien besser unterstützt und etwas einfacher.

(Die PixelMask-Tabelle oben ist glaube ich falsch herum, um 1:40 kann das schon einmal passieren... 😉 )

Grüße!

ich habe jetzt die gesamte Displaylist angepasst und auch die Plotroutine... was noch fehlt ist die schnellere Phasenverschiebung. Leider bin ich am WE unterwegs und kann da nicht weitermachen... zunächst. Das Projekt ist höchst spannend. Ich habe eine Zählerroutine mit reingemacht, damit ich die Geschwindigkeit testen kann.... bislang schafft die Routine ca 90 lange Linien pro Sekunde in Pal. Jetzt das noch weiter optimieren... ich möchte mindestens 150 / Sekunde zeichnen können, dann gehts weiter mit 3D

... ich habe gerade mal die alte Routine für die Phasenverschiebung komplett rausgenommen - die Gerade sieht natürlich jetzt falsch aus, aber die Geschwindigkeit nimmt damit dramatisch zu: Fast 500 Linien pro Sekunde zeichnet die Routine mit dem Bresenham-Algorithmus. Der Bremsklotz ist also die Unterroutine der Phasenverschiebung. Das ahnte ich schon, da ich die Routine ohne Optimierung gebaut habe. Hier gilt es jetzt anzusetzen und da habe ich auch schon einige Ideen. Eigentlich geht ja der Bresenham immer um einen X-Wert voran und ab und zu halt mal um einen Y-Wert nach oben oder unten. Das schnellste wird wohl sein, ein wenig Speicher zu opfern und die Routine einfach 4x hintereinander laufen zu lassen - jeweils mit phasenverschobenen Wert der zu platten ist. Dann gibt es praktische keine relevante Verzögerung und ich hoffe damit auf 300-400 Linien pro Sekunde zu kommen - damit könnte man arbeiten.

Danach programmiere ich die ganzen Spezialfälle (positive Steigung, negative Steigung, jeweils Steigung >1 und <1, horizontale Linie, vertikale Linie, jeweils Steigung genau 1 / -1...... es werden also wohl 10 Fälle jeweils mit 4x Code wegen der Phasenverschiebung. Großer Aufwand - Maximale Geschwindigkeit....

... nochmal ein kurzes Wort zu MADS:

Eingebunden mit WUDSN in Eclipse mit dem Emulator ist das für mich wirklich eine optimale Umgebung, um mit moderner Technik Assemblercode für unseren geliebten Atari zu entwickeln!! Ich könnte mir nichts besseres vorstellen - vielleicht wäre Action! mal interessant. Kann man das in Eclipse einbinden???

[quote="Dr. Irata" post_id=15255 time=1685089261 user_id=250] Kann man das in Eclipse einbinden??? [/quote]

ACTION! läuft auf dem Atari als Cart, da müsste man den Emulator per Script "fernsteuern". Das habe ich noch nicht getestet, ob es einen Emulator gibt, der das kann. Wäre Interessant das mal herauszufinden.

Unter

New Frontiers in High-Level 6502 Programming https://8bitworkshop.com/docs/posts/2018/higher-level-6502-programming.html#higher-level-6502-programming

gibt es eine lange Liste von sehr interessanten (zum Teil neuen) Programmiersprachen für den A8. Ich suche noch Mitstreiter, welche an einer Artikel-Serie für das ABBUC Magazin mitmachen um diese Sprachen zu testen und auch von der Code-Qualität zu vergleichen.

Bei Interesse bitte melden.

https://mastodon.social/@cstrotm https://abbuc.social

... interessant mit den Sprachen, zeitlich schaffe ich das leider im Moment nicht, auch habe ich ja nur Mac und die meisten Entwicklungen laufen nur auf Windows...

Thema Plot/Drawto:

Habe jetzt mal kurz in der Vormittagszeit den Code wie oben geschrieben vervierfacht und so das "Problem" mit der Phasenverschiebung sehr einfach gelöst... Geschwindigkeitszuwachs von ca. 90 Linien/Sekunde auf 220 Linien/Sekunde. Mal sehen, ob ich das noch weiter steigern kann...

... 250 ... mehr geht nicht! Das betrifft natürlich gemessenen Linien, die zwischen mittellang und sehr lang geplottet werden - also die ganze Diagonale des Bildschirmes bei 160/96 Auflösung betrifft. Wenn ich jetzt in einem 3D Spiel von deutlich kürzeren Linien ausgehe, dann schaffe ich so ca. 500-600 Linien oder mehr pro Sekunde. Das weitere Vorgehen wird jetzt sein, eine komplette Plotroutine für alle Gerade zu schreiben, dann möchte ich eine Linie animiert darstellen. Danach wird das ganze fürs nächste Heft aufgearbeitet incl. Dokumentation und Code.

Anschließend wird dieses Thema hier geschlossen und ich gehe weiter in die nächste Planung von 3D TempleOfEris, wo ich zunächst ein reines 3D-Raumgerüst erstellen möchte, was man mit dem Joystick entsprechend der Bewegung durch den Raum steuern kann. Danach kommen die Wandfüllroutinen - also die mögliche Oberfläche (diesen Part stelle ich mir sehr schwierig vor).

Danach sollten (wenn ich überhaupt so weit komme) die Aliens, Schüsse, Kollisionserkennung folgen, dann das gesamte Labyrinthdesign... (in ca. 10 Jahren bin ich dann vielleicht fertig 😂 )

... jetzt habe ich die Plotroutine fertig und alle Spezialfälle (Richtungen, Steigungen) sind drin und funktionieren - ein kleiner Fehler muss noch drin sein habe ich gerade gesehen - und kurz mal eine kleine allerdings nicht sehr gute Routine geschrieben, um eine Linie zu zeichnen und die per Random über den Bildschirm zu bewegen. Damit ist das Kapitel hier fertig... ich arbeite das noch fürs Magazin auf und gehe dann zurück zu Temple Of Eris!

draw.mov

Anhänge:

vielleicht noch per Pageflipping arbeiten und dann Quasi die neue Zeile erst anzeigen wenn sie fertig gezeichnet ist...

... ich habe jetzt auch die Drawfehler raus und mache den Plot jetzt im VBI, damit das etwas besser aussieht (Danke Janko für den Hinweis). Die Bewegung ist zufallsgesteuert und daher nicht so schön "rund", man müsste Bewegungsmuster hinterlegen, damit es eine feine Demo wird, das habe ich jetzt nicht noch gemacht... Hier aber nochmal ein kleiner Ausschnitt aus der Draw-Bewegung:

draw2.mov

Anhänge:

Wozu willst du die Linie eigentlich verwenden?

ursprünglich wollte ich für mein nächstes Spiel schauen, ob es möglich ist eine Art Ego-Shooter zu machen mit einem 3D Labyrinth... da wurde mir schnell klar, daß ich dafür ganz viele Linien zeichnen lassen muss. Linien zeichnen in Assembler - gar nicht so einfach. Daher jetzt dieser Beitrag incl. Bresenham- Algorithmus. Ob ich das am Ende hinbekomme? Fraglich... erstmal alles im Rahmen einer Machbarkeitsstudie 😉

sehr cool... allerdings brauche ich jetzt noch einen Füllalgorithmus 😉

Dr. Irata schrieb: sehr cool... allerdings brauche ich jetzt noch einen Füllalgorithmus 😉

Na ja, wenn Du ein ausgefülltes "Labyrinth" haben möchtest, brauchst Du keine Linienzeichenroutine. Der einzig gangbare Weg, so etwas einigermaßen zügig auf dem Atari hinzubekommen ist ein sogenannter "Raycaster". Zu diesem Thema gibt es sehr viel Literatur, Youtube-Tutorials, Beispielcode.

Deine Linienroutine ergibt allerdings Sinn, falls Du eine Drahtgitter 3d-Umgebung erstellen möchtest. Dann brauchst Du aber keinen 'Füllalgorithmus'...

... bin mir da noch nicht so ganz sicher, wie es wird.... zunächst probiere ich mal aus die Flächen auch mit vertikalen Drawlinien zu "füllen" - so war mein Plan. Die Routinen sind ja schnell und einfach und wenn ich die schrägen Geraden zeichne, dann kann ich gleichzeitig die Linien mit vertikalen verbinden. Ob das gut funktioniert, weiß ich nicht... so etwas habe ich ja noch nie gemacht.

Das Thema lässt mich nicht los ... heute gab es auf HackerNews (https://news.ycombinator.com) einen Link zu diesem Blog-Post

BRR Lines A new line drawing method for the cycle savvy http://www.quiss.org/boo/

Dort hat jemand aus dem C64-Land einen Linien-Algorithmus, welcher oft schneller als Bresenham ist. Ist C64, also anderer Speicher-Layout, aber vielleicht für den A8 adaptierbar.

https://mastodon.social/@cstrotm https://abbuc.social

vielen Dank ... mega spannend

Hi, hier mal eine simple Line-Demo.

LINE-DEMO.XEX

Die zeichnet 17 Pixel auf den Screen. Die Pixel bewegen sich alle gleich schnell in unterschiedliche Richtungen. Erreicht ein Pixel den Rand, fängt er wo anders wieder an.

Wenn der Abstand zwischen 2 Pixeln eine gewisse Schwelle erreicht hat, wird zwischen ihnen eine Linie gezeichnet. Je nach Abstand unterschiedlich hell. Der Algorithmus für die Abstände ist teuer (~O(n^2/2))

Als Line-Routine hab ich die von ERU verwendet (mal in AtariAge gefunden), da dieser saubere Linien zeichnet. Die Rattenschnelle Line-Version hab ich auch mal probiert, aber die Animation ist nicht merklich flotter, dafür fällt extrem stark auf, wie schlecht der Line-Algorithmus wirklich ist.

Als DoubleBuffer habe ich mir etwas zusammengezimmert, es ist nicht perfekt, aber besser als Flackern oder immer den ganzen Screen kopieren.

Nett anzusehen, aber als Speed-Test nicht zu gebrauchen.

LG Lars

Anhänge:

... wie funktioniert denn der Algorithmus von Eru??

Neues Video über schnelle Computergrafik von PCRetroTech:

Animating Ellipses on a Vintage 386 Computer https://www.youtube.com/watch?v=d8ulXJZD0P8

erklärt die Algorithmen hinter Linien, Kreise und Ellipsen

https://mastodon.social/@cstrotm https://abbuc.social

.... nach längerer Zeit doch nochmal ein Aspekt zu diesem Thema:

In meinem Raycaster beschäftige ich mich ja gerade mit der Frage, wie kann ich die Wände besser darstellen. Dazu will ich jetzt Bresenham und eine Art Plot / Drawto - Option einbauen und nutzen. Also habe ich mich zwangsläufig wieder mit Bresenham beschäftigt und wollte gerade die alten Algorithmen rauskramen und dann in den Code einbauen. Dann kam mir aber die Erkenntnis, daß ich damals ja schon Bresenham in meinem Raycaster drin habe, allerdings nicht als Algorithmus (mit langwieriger Rechenzeit), sondern als Tabelle. Da sind also vorgefertige "Strahlen" mit voller Rotation um 360 Grad, kostet knapp 2,5 kB Diese "Strahlen" müsste man ja dann aber auch für eine Drawto-Routine nutzen können und das dürfte echt schnell sein... das werde ich hier zunächst mal bauen!

Also eine neue sehr schnelle Drawto-Routine in Assembler....